 #include "visbasecontainer.h"
//#include "visbaseelement.h"
//#include "visbasewidget.h"
//#include "SageVis/sagevis.h*/"

//#include "visbaseelement.h"
#include "SageVis/sagevis.h"
#include "visbasewidget.h"
#include "SageVis/VisBaseClasses/visbaselayout.h"


VisBaseContainer::VisBaseContainer( QPointer<SageVis> sageVisPointer, QPointer<VisBaseWidget> parentWidget, QGraphicsItem *parent ) :
    VisBaseElement( sageVisPointer, parentWidget, parent ) //sageVisPointer( sageVisPointer ), parentWidget(parentWidget), QGraphicsWidget(parent)
{
    layout = NULL;
    containerBoundingRect.setCoords(0, 0, 0, 0);//I dont think I am using this right now

    //this is the mechanism by which vis base containers run a layout in a separate thread- their parent's thread
    //  once the layout is created, and all genome elements are added, this layout is passed to the parent widget
    //  and the layout is run on the separate thread.
    connect( this, SIGNAL(runLayoutSignal(VisBaseLayout*)), parentWidget, SLOT( runLayoutSlot(VisBaseLayout*)));
}

//VisBaseContainer::~VisBaseContainer()
//{
//    if( layout != 0 )
//        delete layout;
//}

//------------------------------SLOTS----------------------------------------------
void VisBaseContainer::advance()
{

}

void VisBaseContainer::callUpdate()
{
    update();
}

void VisBaseContainer::clearAndDelete()
{
//    int numElts = elements.size();
//    for (int i=0; i<numElts; i++)
//    {
//        QPointer< VisBaseElement > vbe = elements.takeAt(0);
//        if( vbe )
//            delete vbe;
//    }
//    elements.clear();
    qDebug() << "Before Container.size = " << elements.size();


    if( layout != NULL )
    {
        layout->clear();
        delete layout;
        layout = NULL;
        elements.clear();
        hashedElements.clear();
    }
    else
    {
        qDeleteAll(elements);
        elements.clear();

        hashedElements.clear();
    }
    qDebug() << "After Container.size = " << elements.size();


    //delete elements
    while( !elements.isEmpty() )
    {
        QPointer<VisBaseElement> elt = elements.takeFirst();
        if( !elt )
        {
            delete elt;
        }
    }

    hashedElements.clear();

    if( layout )
    {
        //layout->clear();
        delete layout;
    }





}

void VisBaseContainer::recomputeLayoutSlot()
{
    //qDebug() << "recompute layout" << endl;
    layoutElements();
}

void VisBaseContainer::moveLayoutBackToThisThread()
{
    //if( layout ) //should always be true if slot called properly
        //layout->moveToThread(this->thread());
}

//------------------------------ADD ELEMENTS---------------------------------------
void VisBaseContainer::addElement(QPointer<VisBaseElement> e)
{
    elements << e;
    hashedElements.insert(e->getUniqueId(), elements.size()-1); //hash id to idx
    connect( e, SIGNAL(recomputeLayoutSignal()), this, SLOT(recomputeLayoutSlot()) );//ensure that if child can signal parent to layout again                                                                                //in the event of a change in height
}

void VisBaseContainer::prepend(QPointer<VisBaseElement> e)
{
    elements.prepend(e);//prepend elt to the list
    connect( e, SIGNAL(recomputeLayoutSignal()), this, SLOT(recomputeLayoutSlot()) );//ensure that if child can signal parent to layout again                                                                                //in the event of a change in height

    hashedElements.insert(e->getUniqueId(), 0); //hash id to idx=0

    //then update indices
    for(int i = 1; i < elements.size(); i++)
    {
        QString id = elements[i]->getUniqueId();//get id
        hashedElements.remove(id);//remove old value for that elt
        hashedElements.insert(id, i );//add with correct idx
    }

    //hashedElements.insert()
}

VisBaseElement* VisBaseContainer::getElement(int idx)
{
    if( idx >= elements.size() )
        return NULL;
    if( idx < 0 )
        return NULL;
    return elements[idx];
}

VisBaseElement* VisBaseContainer::getElement(QString key)
{
    int idx = hashedElements.value(key);
    if( idx >= elements.size() )
        return NULL;
    if( idx < 0 )
        return NULL;
    return elements[idx];
}

bool VisBaseContainer::containsElement(QString key)
{
    return hashedElements.contains(key);
}


int VisBaseContainer::getNumElements()
{
    return elements.size();
}


bool VisBaseContainer::removeElement(int idx)
{
    if( idx < 0 || idx >= elements.size())
        return false;

    //first remove the element
    hashedElements.take(elements[idx]->getUniqueId() );
    elements.removeAt(idx);

    //then update indices
    for(int i = idx; i < elements.size(); i++)
    {
        QString id = elements[i]->getUniqueId();//get id
        hashedElements.remove(id);//remove old value for that elt
        hashedElements.insert(id, i );//add with correct idx
    }

    return true;
}

bool VisBaseContainer::removeElement(QString key)
{
    //first remove the element
    int idx = hashedElements.take(key);
    if( idx == -1 )
        return false;
    elements.removeAt(idx);

    //then update indices
    for(int i = idx; i < elements.size(); i++)
    {
        QString id = elements[i]->getUniqueId();//get id
        hashedElements.remove(id);//remove old value for that elt
        hashedElements.insert(id, i );//add with correct idx
    }
    return true;
}

bool VisBaseContainer::removeAndPrepend(int idx)
{
    if( idx < 0 || idx >= elements.size())
        return false;
    VisBaseElement* elt = elements.takeAt(idx);//remove
    elements.prepend(elt);//prepend
    connect( elt, SIGNAL(recomputeLayoutSignal()), this, SLOT(recomputeLayoutSlot()) );//ensure that if child can signal parent to layout again                                                                                //in the event of a change in height
        //I don't think this is necessary...

    //remove the 5th, move to front.
    //idx changes:  0->1, 1->2, 2->3, 3->4, 4->5, 5->0
    for(int i = 0; i < idx; i++)
    {
        QString id = elements[i]->getUniqueId();//get id
        hashedElements.remove(id);//remove old value for that elt
        hashedElements.insert(id, i );//add with correct id
    }

    return true;
}


bool VisBaseContainer::removeAndPrepend(QString key)
{
    //first remove the element
    int idx = hashedElements.take(key);
    if( idx == -1 )
    {
        qDebug() << "attempting to remove and prepend- failed" << endl;
        return false;
    }

    VisBaseElement* elt = elements.takeAt(idx);
    elements.prepend(elt);//prepend

    //remove the 5th, move to front.
    //idx changes:  0->1, 1->2, 2->3, 3->4, 4->5, 5->0
    for(int i = 0; i < idx; i++)
    {
        QString id = elements[i]->getUniqueId();//get id
        hashedElements.remove(id);//remove old value for that elt
        hashedElements.insert(id, i );//add with correct id
    }
}

//-------------------CONNECT ELEMENTS AND CONTAINER-------------------------------
void VisBaseContainer::connectContainerToElements(int type)
{
    for(int i = 0 ; i < elements.size(); i++ )
    {
        this->forgeConnection(elements[i], type);
    }
}

void VisBaseContainer::connectElementsToContainer(int type)
{

    for(int i = 0 ; i < elements.size(); i++ )
    {
        elements[i]->forgeConnection(this, type);
    }
}

void VisBaseContainer::connectTwoWayElementsToContainer(int type)
{
    for(int i = 0 ; i < elements.size(); i++ )
    {
        forgeConnection(this, elements[i], type);
        forgeConnection(elements[i], this, type);
    }
}

//-------------------SET HEIGHT, WIDTH, XPos, YPos---------------------------------
    //--------FLOAT----------------------------------------------------------------
//give elements uniform width
void VisBaseContainer::setWidthOfElements( float w )
{
    for(int i = 0; i < elements.size(); i++ )
    {
        elements[i]->setWidth(w);
    }
}

//give elements uniform height
void VisBaseContainer::setHeightOfElements( float h )
{
    for(int i = 0; i < elements.size(); i++ )
    {
        elements[i]->setHeight(h);
    }
}

void VisBaseContainer::setWidthAndHeightOfElements(float w, float h)
{
    for(int i = 0; i < elements.size(); i++ )
    {
        elements[i]->setHeight(h);
        elements[i]->setWidth(w);
    }
}

//line up vertically
void VisBaseContainer::setXPosOfElements( float xPos )
{
    for(int i = 0; i < elements.size(); i++ )
    {
        elements[i]->setPos( xPos, elements[i]->pos().y() );
    }
}

//line up horizontally
void VisBaseContainer::setYPosOfElements( float yPos )
{
    for(int i = 0; i < elements.size(); i++ )
    {
        elements[i]->setPos( elements[i]->pos().x(), yPos );
    }
}

//stacked atop each other
void VisBaseContainer::setPosOfElements( float x, float y )
{
    for(int i = 0; i < elements.size(); i++ )
    {
        elements[i]->setPos( x, y );
    }
}

    //--------INT----------------------------------------------------------------
//give elements uniform width
void VisBaseContainer::setWidthOfElements( int w )
{
    setWidthOfElements( (float) w);
}

//give elements uniform height
void VisBaseContainer::setHeightOfElements( int h )
{
    setHeightOfElements( (float) h);
}

void VisBaseContainer::setWidthAndHeightOfElements(int w, int h )
{
    setWidthAndHeightOfElements( (float) w, (float) h);
}

//line up vertically
void VisBaseContainer::setXPosOfElements( int xPos )
{
    setXPosOfElements( (float) xPos );
}

//line up horizontally
void VisBaseContainer::setYPosOfElements( int yPos )
{
    setYPosOfElements( (float) yPos );
}

//stacked atop each other
void VisBaseContainer::setPosOfElements( int x, int y )
{
    setPosOfElements( (float) x, (float) y );
}
//-------------------GET MAX WIDTH ---------------------------------
//find the maxWidth of elements
float VisBaseContainer::getMaxElementWidth()
{
    maxElementWidth = -1.0;
    for(int i = 0; i < elements.size(); i++)
    {
        if( elements[i]->boundingRect().width() > maxElementWidth )
            maxElementWidth = elements[i]->boundingRect().width() ;
    }
    return maxElementWidth;
}

//-------------------------------SIZE AND SHAPE-----------------------------------
//void VisBaseContainer::setGeometry(const QRectF &geom)
//{
//    prepareGeometryChange();
//    QGraphicsWidget::setGeometry(geom);
//    setPos(geom.topLeft());
//}

//void VisBaseContainer::setGeometry(qreal x, qreal y, qreal w, qreal h)
//{
//    setGeometry(QRect(x, y, w, h));
//}

//QRectF VisBaseContainer::boundingRect() const
//{
//    return QRectF(QPointF(0,0), geometry().size());
//}


//QPainterPath VisBaseContainer::shape() const
//{
//    QPainterPath path;
//    path.addRect(boundingRect());
//    return path;
//}

//---------------------------------LAYOUT--------------------------------------------
void VisBaseContainer::setLayout(VisBaseLayout *l)
{
//    if( layout != NULL )
//    {
//        layout->clear();
//        delete layout;
//    }

    layout = l;
    layout->addElements(elements);
}

VisBaseLayout* VisBaseContainer::getLayout()
{
    return layout;
}

void VisBaseContainer::layoutElements()
{
    emit( runLayoutSignal(layout) );
}

void VisBaseContainer::layoutElements(VisBaseLayout* layout)
{
    layout->addElements(elements);
    emit( runLayoutSignal(layout) );
}

void VisBaseContainer::layoutElementsNonThreaded()
{
    layout->process();
    update();
}

void VisBaseContainer::layoutElementsNonThreaded(VisBaseLayout* layout)
{
    layout->addElements(elements);
    layout->process();
    update();
}




